#include "stdafx.h"

#ifdef _DEBUG

#include "log.h"

//un-comment this line if you get an error:
//Unresolved ... NKDbgPrintfW...
//extern "C" void WINAPIV NKDbgPrintfW(LPWSTR lpszFmt, ...);

struct _CrtFileName {
	wchar_t*	_CrtName;
	_CrtFileName*	_CrtNext;
};

struct _CrtMem {
	_CrtFileName*	_CrtFileName;
	int				_CrtLine;
	unsigned int	_CrtMemLen;
	void*			_CrtMemAddr;
	_CrtMem*		_CrtNext;
};

class garbageLogger {
public:
	garbageLogger () {}
	~garbageLogger ();
};

_CrtMem*			_CrtMemRoot = 0;
_CrtFileName*		_CrtFileNameRoot = 0;
unsigned long		maxMem = 0;
unsigned long		currMem = 0;

garbageLogger gb;

void* operator new(
        size_t s,
        wchar_t* name,
        int line
        )
{
	void*	retPtr = malloc (s);
	if (retPtr)
  {
		currMem += s;
		if (currMem > maxMem)
		{
			maxMem = currMem;
		}
		_CrtMem*	_crtMemCell = (struct _CrtMem*)malloc (sizeof(_CrtMem));
		_crtMemCell->_CrtLine		= line;
		_crtMemCell->_CrtMemLen		= s;
		_crtMemCell->_CrtMemAddr	= retPtr;
		_crtMemCell->_CrtNext		= 0;

		_CrtFileName*	_tmpCrtFileName;
		for (_tmpCrtFileName = _CrtFileNameRoot; _tmpCrtFileName && wcscmp(name, _tmpCrtFileName->_CrtName); _tmpCrtFileName = _tmpCrtFileName->_CrtNext);
		if (!_tmpCrtFileName)
    {
			wchar_t*	_crtName = (wchar_t*)malloc ((wcslen (name) + 1) * sizeof(wchar_t));
			wcscpy (_crtName, name);
			_CrtFileName*	_crtFileName = (struct _CrtFileName*)malloc (sizeof (_CrtFileName));
			_crtFileName->_CrtName = _crtName;
			_crtFileName->_CrtNext = 0;
			if (!_CrtFileNameRoot)
				_CrtFileNameRoot = _crtFileName;
			else
      {
				for (_tmpCrtFileName = _CrtFileNameRoot; _tmpCrtFileName->_CrtNext; _tmpCrtFileName = _tmpCrtFileName->_CrtNext);
				_tmpCrtFileName->_CrtNext = _crtFileName;
			}
			_tmpCrtFileName = _crtFileName;
		}
		_crtMemCell->_CrtFileName = _tmpCrtFileName;

#ifdef LOG_ENABLED
    Logger::LogTimestamp();
    Logger::LogFmt(TEXT("--------------> NEW: %s(%i) : normal block at 0x%08X, %i bytes long"), _crtMemCell->_CrtFileName->_CrtName, _crtMemCell->_CrtLine, _crtMemCell->_CrtMemAddr, _crtMemCell->_CrtMemLen);
    if (_crtMemCell->_CrtMemLen > 1024)
      Logger::Log(TEXT("//////////////// LARGE"));
#endif

		if (!_CrtMemRoot)
    {
			_CrtMemRoot		= _crtMemCell;
		}
		else
    {
			_CrtMem*	_tmpMemPtr;
			for (_tmpMemPtr = _CrtMemRoot; _tmpMemPtr->_CrtNext; _tmpMemPtr = _tmpMemPtr->_CrtNext);
			_tmpMemPtr->_CrtNext = _crtMemCell;
		}
	}

	return retPtr;

}

void __cdecl operator delete(void *pvMem, wchar_t* name, int line)
{
  name;
  line;
	if (pvMem)
  {
		_CrtMem*	_tmpMem;
		if (pvMem == _CrtMemRoot->_CrtMemAddr)
    {
			_tmpMem			= _CrtMemRoot;
			_CrtMemRoot		= _CrtMemRoot->_CrtNext;
			currMem -= _tmpMem->_CrtMemLen;
#ifdef LOG_ENABLED
    Logger::LogTimestamp();
    Logger::LogFmt(TEXT("==============> DELETE: %s(%i) : normal block at 0x%08X, %i bytes long"), _tmpMem->_CrtFileName->_CrtName, _tmpMem->_CrtLine, _tmpMem->_CrtMemAddr, _tmpMem->_CrtMemLen);
    if (_tmpMem->_CrtMemLen > 1024)
      Logger::Log(TEXT("\\\\\\\\\\\\\\\\ LARGE"));
#endif
			free (_tmpMem);
		}
		else
    {
			for (_tmpMem = _CrtMemRoot; _tmpMem->_CrtNext && (_tmpMem->_CrtNext->_CrtMemAddr != pvMem); _tmpMem = _tmpMem->_CrtNext);
			if (_tmpMem->_CrtNext)
      {
				_CrtMem*	_tmpMem2;
				_tmpMem2	= _tmpMem->_CrtNext;
				_tmpMem->_CrtNext = _tmpMem2->_CrtNext;
				currMem -= _tmpMem2->_CrtMemLen;
#ifdef LOG_ENABLED
    Logger::LogTimestamp();
    Logger::LogFmt(TEXT("==============> DELETE: %s(%i) : normal block at 0x%08X, %i bytes long"), _tmpMem2->_CrtFileName->_CrtName, _tmpMem2->_CrtLine, _tmpMem2->_CrtMemAddr, _tmpMem2->_CrtMemLen);
    if (_tmpMem2->_CrtMemLen > 1024)
      Logger::Log(TEXT("\\\\\\\\\\\\\\\\ LARGE"));
#endif
				free (_tmpMem2);
			}
			else
				NKDbgPrintfW (_T("%s(%i) : Warning : deletes memory pointer not allocated with new!\n"), _T(__FILE__), __LINE__);
		}
		free (pvMem);
	}
}

void* operator new[](
        size_t s,
        wchar_t* name,
        int line
        )
{
	return operator new(s, name, line);
}

void __cdecl operator delete[](void *pvMem, wchar_t* name, int line)
{
  return operator delete(pvMem, name, line);
}

garbageLogger::~garbageLogger()
{
	if (!_CrtMemRoot)
  {
		NKDbgPrintfW (_T("No memory leaks detected!\n"));
#ifdef LOG_ENABLED
    Logger::Log(_T("No memory leaks detected!\n"));
#endif
  }
	else
  {
		_CrtMem*	_tmpMem;
		NKDbgPrintfW (_T("Detected memory leaks!\nDumping objects ->\n"));
#ifdef LOG_ENABLED
    Logger::Log(_T("Detected memory leaks!\nDumping objects ->\n"));
#endif
		for (_tmpMem = _CrtMemRoot; _tmpMem; _tmpMem = _tmpMem->_CrtNext)
    {
			NKDbgPrintfW (_T("%s(%i) : normal block at 0x%08X, %i bytes long\n Data <"), _tmpMem->_CrtFileName->_CrtName, _tmpMem->_CrtLine, _tmpMem->_CrtMemAddr, _tmpMem->_CrtMemLen);
#ifdef LOG_ENABLED
      Logger::LogFmt(_T("%s(%i) : normal block at 0x%08X, %i bytes long\n Data <"), _tmpMem->_CrtFileName->_CrtName, _tmpMem->_CrtLine, _tmpMem->_CrtMemAddr, _tmpMem->_CrtMemLen);
#endif
			unsigned int _length = _tmpMem->_CrtMemLen < 100 ? _tmpMem->_CrtMemLen : 50;
			for (unsigned int i = 0; i < _length; i++)
      {
				NKDbgPrintfW (_T("%c"), *(((char*)_tmpMem->_CrtMemAddr)+i));
#ifdef LOG_ENABLED
        Logger::LogFmt(_T("%c"), *(((char*)_tmpMem->_CrtMemAddr)+i));
#endif
      }
			NKDbgPrintfW (_T(">\n"));
#ifdef LOG_ENABLED
      Logger::Log(_T(">\n"));
#endif
		}
	}
	_CrtFileName*	_tmpName = _CrtFileNameRoot;
	for (;_tmpName;)
  {
		_CrtFileNameRoot	= _tmpName->_CrtNext;
		free(_tmpName->_CrtName);
		free(_tmpName);
		_tmpName			= _CrtFileNameRoot;
	}

	NKDbgPrintfW (_T("Maximum free store memory allocated at a time: %lu!\n"), maxMem);
#ifdef LOG_ENABLED
  Logger::LogFmt(_T("Maximum free store memory allocated at a time: %lu!\n"), maxMem);
#endif
}

#endif